﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace UtilZ.Dotnet.Ex.TTLV
{
    /// <summary>
    /// TLV编解码类
    /// </summary>
    public class TTLVNodeCustomCodec : ITTLVNodeCodec
    {
        /***********************************************************************************************************
         * 名称	            类型	        标记:Tag	                长度:Length	        值范围:Value
         * 
         * 布尔	            Boolean	        10进制:1, 2进制:00000001	1	                1:true .. 0:false
         * 小整型	        Tiny	        10进制:2, 2进制:00000010	1	                -127 .. 127
         * 无符号小整型	    UTiny	        10进制:3, 2进制:00000011	1	                0 .. 255
         * 短整型	        Short	        10进制:4, 2进制:00000100	2	                -32768 .. 32767
         * 无符号短整型	    UShort	        10进制:5, 2进制:00000101	2	                0 .. 65535
         * 
         * 整型	            Integer	        10进制:6, 2进制:00000110	4	                -2147483648 .. 2147483648
         * 无符号整型	    UInteger	    10进制:7, 2进制:00000111	4	                0 .. 4294967295
         * 长整型	        Long	        10进制:8, 2进制:00001000	8	                -2^64 .. 2^64
         * 无符号长整型	    ULong	        10进制:9, 2进制:00001001	8	                0 .. 2^128-1
         * 单精浮点类型	    Float	        10进制:10, 2进制:00001010	4	                -2^128 .. 2^128
         * 
         * 双精浮点类型	    Double	        10进制:11, 2进制:00001011	8	                -2^1024 .. 2^1024
         * 字符类型	        Char	        10进制:12, 2进制:00001100	1	                ASCII
         * 字符串类型	    String	        10进制:13, 2进制:00001101	可变	            由一个或多个Char组成
         * 组合类型	        Complex	        10进制:14, 2进制:00001110	可变	            由一个或多个基本类型1~9组成，由协议两端双方进行约定编解码
         * 空类型	        Null	        10进制:15, 2进制:00001111	0	
         ***********************************************************************************************************/

        private readonly Dictionary<TypeCode, byte> _typeCodeMapDic = new Dictionary<TypeCode, byte>();
        private readonly Dictionary<byte, TypeCode> _typeCodeMapDic2 = new Dictionary<byte, TypeCode>();

        /// <summary>
        /// 构造函数
        /// </summary>
        public TTLVNodeCustomCodec()
        {
            this._typeCodeMapDic.Add(TypeCode.Boolean, 1);
            this._typeCodeMapDic.Add(TypeCode.SByte, 2);
            this._typeCodeMapDic.Add(TypeCode.Byte, 3);
            this._typeCodeMapDic.Add(TypeCode.Int16, 4);
            this._typeCodeMapDic.Add(TypeCode.UInt16, 5);

            this._typeCodeMapDic.Add(TypeCode.Int32, 6);
            this._typeCodeMapDic.Add(TypeCode.UInt32, 7);
            this._typeCodeMapDic.Add(TypeCode.Int64, 8);
            this._typeCodeMapDic.Add(TypeCode.UInt64, 9);
            this._typeCodeMapDic.Add(TypeCode.Single, 10);

            this._typeCodeMapDic.Add(TypeCode.Double, 11);
            this._typeCodeMapDic.Add(TypeCode.Char, 12);
            this._typeCodeMapDic.Add(TypeCode.String, 13);
            this._typeCodeMapDic.Add(TypeCode.Object, 14);
            this._typeCodeMapDic.Add(TypeCode.Empty, 15);

            foreach (var kv in this._typeCodeMapDic)
            {
                this._typeCodeMapDic2.Add(kv.Value, kv.Key);
            }
        }

        /// <summary>
        /// 顺序编码节点数据
        /// </summary>
        /// <param name="bw">BinaryWriter</param>
        /// <param name="tag">Tag</param>
        /// <param name="typeCode">Type</param>
        /// <param name="valueBuffer">Value</param>
        public void WriteNode(BinaryWriter bw, int tag, TypeCode typeCode, byte[] valueBuffer)
        {
            bw.Write(BitConverter.GetBytes(tag));

            byte type;
            if (!this._typeCodeMapDic.TryGetValue(typeCode, out type))
            {
                type = (byte)typeCode;
            }

            bw.Write(type);
            bw.Write(BitConverter.GetBytes(valueBuffer.Length));
            bw.Write(valueBuffer);
        }

        /// <summary>
        /// 读取节点信息
        /// </summary>
        /// <param name="br">BinaryReader</param>
        /// <param name="nodeInfo">存储节点信息对象</param>
        public void ReadNodeInfo(BinaryReader br, TTLVNodeInfo nodeInfo)
        {
            nodeInfo.Tag = br.ReadInt32();

            byte type = br.ReadByte();
            TypeCode typeCode;
            if (!this._typeCodeMapDic2.TryGetValue(type, out typeCode))
            {
                typeCode = (TypeCode)type;
            }
            nodeInfo.Type = typeCode;

            nodeInfo.Length = br.ReadInt32();
        }
    }
}
